<template>
  <div class="form-content">
    <el-form class="form-content__form"
     ref="ruleForm" :model="formSource.ruleForm" :rules="formSource.rules"
     :inline="formOptions.inline" :size="formOptions.size"
     :label-position="formOptions.labelPosition"
     :label-width="formOptions.labelWidth"
     :label-suffix="formOptions.labelSuffix">

      <template v-for="(_item, _index) in formSource.operations">
        <el-form-item v-if="_item.show" :label="_item.name ? _item.name + ':' : ''"
         v-bind:key="_index" :prop="_item.key"
         :label-width="_item.labelWidth" :style="{ width: _item.formWidth }">
          <!-- 占位 -->
          <span v-if="_item.type === 'place'" class="form-content__operation-item-span" :style="{ width: _item.width }"></span>
          <!-- 内容 -->
          <span v-if="_item.type === 'content'" class="form-content__operation-item-span" :style="{ width: _item.width }">{{ formSource.ruleForm[_item.key] }}</span>
          <!-- 文本框控件 -->
          <el-input v-if="_item.type === 'text'" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled"
           :show-password="_item.showPassword || false" :maxlength="_item.length || 15"
           :placeholder="_item.placeholder || ''" :size="formOptions.size"
           @input="changeHandle(_item, _index)" @focus="showHandle(_item, _index, $event)" @clear="clearHandle(_item, _index)"
           clearable>
          </el-input>
          <!-- 输入框匹配控件 -->
          <el-autocomplete v-if="_item.type === 'autocomplete'" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled" :maxlength="_item.length || 30"
           :placeholder="_item.placeholder || '请输入或选择内容'" :size="formOptions.size"
           @input="changeHandle(_item, _index)" :fetch-suggestions="querySearch" @focus="setAutocompleteArr(_item, _index)"
           @select="autoSelectHandle(_item)" @clear="clearHandle(_item, _index)"
           clearable>
          </el-autocomplete>
          <!-- 计数控件 -->
          <el-input-number v-if="_item.type === 'number'" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled"
           :controls-position="_item.numberControlsPosition || ''" :size="formOptions.size"
           :step="_item.numberStep || 1" :min="_item.numberMin || 1" :max="_item.numberMax || 100"
           @change="changeHandle(_item, _index)">
          </el-input-number>
          <!-- 文本域控件 -->
          <el-input v-if="_item.type === 'textarea'" type="textarea" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled"
           :placeholder="_item.placeholder || ''" :size="formOptions.size"
           :rows="_item.row || 2" @input="changeHandle(_item, _index)"
           clearable>
          </el-input>

          <!-- 头像 -->
          <el-avatar v-if="_item.type === 'avatar'" :style="{ width: _item.width || '60px', height: _item.height || '60px' }"
           :src="formSource.ruleForm[_item.key]" :size="_item.avatarSize || 'large'" :key="formSource.ruleForm[_item.key]"
           :shape="_item.avatarShape || 'circle'" :fit="_item.avatarFit || 'cover'"
           @error="true">
            <img :src="defaultAvatar"/>
          </el-avatar>

          <!-- 开关 -->
          <el-switch v-if="_item.type === 'switch'" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled"
           :active-value="_item.switchAactiveValue || true" :inactive-value="_item.switchInactiveValue || false"
           :validate-event="_item.switchValidate || true" :size="formOptions.size"
           @change="changeHandle(_item, _index)">
          </el-switch>

          <!-- 标签 -->
          <template v-if="_item.type === 'tag'">
            <el-tag :style="{ width: _item.width || '' }"
             v-for="item in formSource.ruleForm[_item.key]" :key="item.value"
             :type="_item.tagType || 'danger'" :closable="_item.tagClosable || false"
             :disabled="_item.disabled" :size="formOptions.size"
             @close="changeHandle(_item, _index, item)">
              {{ item.key }}
            </el-tag>
          </template>

          <!-- 级联选择器控件 -->
          <el-cascader v-if="_item.type === 'cascader'" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled" :size="formOptions.size"
           :options="_item.cascaderOptions" :props="_item.cascaderProps"
           :show-all-levels="_item.cascaderShowAllLevels || false" :filterable="_item.cascaderFilterable"
           @change="changeHandle(_item, _index)" clearable>
          </el-cascader>

          <!-- svg控件 -->
          <IconSvg v-if="_item.type === 'svg'" :width="_item.width || '16px'"
           :height="_item.height || _item.width || '16px'"
           :name="formSource.ruleForm[_item.key] || ''" :class="_item.className">
          </IconSvg>

          <!-- 下拉框控件 -->
          <!-- 下拉框 -->
          <el-select v-if="_item.type === 'select'" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled" :multiple="_item.multiple"
           :filterable="_item.filterable" :collapse-tags="_item.collapseTags"
           :placeholder="_item.placeholder || '请选择'" :size="formOptions.size"
           @change="changeHandle(_item, _index, _item.list.filter(item => {return item.key == _item.value}))" clearable>
            <el-option v-for="item in _item.list" :key="item.key" :label="item.key" :value="item.value" :disabled="item.disabled"></el-option>
          </el-select>
          <!-- 下拉年框 -->
          <el-select v-if="_item.type === 'selectyear'" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled"
           :placeholder="_item.placeholder || '请选择'" :size="formOptions.size"
           @change="changeHandle(_item, _index)" clearable>
            <el-option v-for="item in formatYear()" :key="item.key" :label="item.key" :value="item.value"></el-option>
          </el-select>
          <!-- 下拉月框 -->
          <el-select v-if="_item.type === 'selectmonth'" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled"
           :placeholder="_item.placeholder || '请选择'" :size="formOptions.size"
           @change="changeHandle(_item, _index)" clearable>
            <el-option v-for="item in _item.list || formatMonth()" :key="item.key" :label="item.key" :value="item.value"></el-option>
          </el-select>
          <!-- 下拉月区间框 -->
          <template v-if="_item.type === 'selectmonthrange'">
            <el-select :style="{ width: _item.width || '148px' }"
             v-model.trim="formSource.ruleForm['min' + _item.key.charAt(0).toUpperCase() + _item.key.slice(1)]" :disabled="_item.disabled"
             :size="formOptions.size" :placeholder="_item.placeholder || '请选择'"
             @change="changeHandle(_item, _index, 'start')" clearable>
              <el-option v-for="item in _item.list || formatMonth()" :key="item.key" :label="item.key" :value="item.value"></el-option>
            </el-select>
            <label style="fontSize:12px;color:#7B7F83">{{ _item.go || '至' }}</label>
            <el-select :style="{ width: _item.width || '148px' }"
             v-model.trim="formSource.ruleForm['max' + _item.key.charAt(0).toUpperCase() + _item.key.slice(1)]" :disabled="_item.disabled"
             :size="formOptions.size" :placeholder="_item.placeholder || '请选择'"
             @change="changeHandle(_item, _index, 'end')" clearable>
              <el-option v-for="item in _item.list || formatMonth()" :key="item.key" :label="item.key" :value="item.value"></el-option>
            </el-select>
          </template>

          <!-- 单选框控件 -->
          <el-radio-group v-if="_item.type === 'radio'" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled"
           :size="formOptions.size" :placeholder="_item.placeholder || ''"
           @change="changeHandle(_item, _index)" clearable>
            <template v-for="item in _item.list">
              <el-radio :key="item.key" :label="item.key">{{ item.value }}</el-radio>
            </template>
          </el-radio-group>

          <!-- 时间控件 -->
          <el-date-picker v-if="_item.type === 'date'" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled" align="right"
           :type="_item.type" :value-format="'yyyy-MM-dd'"
           :size="formOptions.size" :placeholder="_item.placeholder || '选择日期'"
           @input="changeHandle(_item, _index)" clearable>
          </el-date-picker>
          <el-date-picker v-if="_item.type === 'datetime'" :style="{ width: _item.width || '180px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled" align="right"
           :type="_item.type" :value-format="'yyyy-MM-dd HH:mm:ss'"
           :size="formOptions.size" :placeholder="_item.placeholder || '选择日期'"
           @input="changeHandle(_item, _index)" clearable>
          </el-date-picker>
          <el-date-picker v-if="_item.type === 'daterange'" :style="{ width: _item.width || '250px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled" align="right"
           :type="_item.type" :value-format="'yyyy-MM-dd'" range-separator="-"
           :size="formOptions.size" :placeholder="_item.placeholder || '选择日期'"
           @input="changeHandle(_item, _index)" clearable>
          </el-date-picker>
          <el-date-picker v-if="_item.type === 'datetimerange'" :style="{ width: _item.width || '250px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled" align="right"
           :type="_item.type" :value-format="'yyyy-MM-dd HH:mm:ss'" range-separator="-"
           :size="formOptions.size" :placeholder="_item.placeholder || '选择日期'"
           @input="changeHandle(_item, _index)" clearable>
          </el-date-picker>
          <el-date-picker v-if="_item.type === 'year'" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled" align="right"
           :type="_item.type"
           :size="formOptions.size" :placeholder="_item.placeholder || '选择年'"
           @input="changeHandle(_item, _index)" clearable>
          </el-date-picker>
          <el-date-picker v-if="_item.type === 'month'" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled" align="right"
           :type="_item.type"
           :size="formOptions.size" :placeholder="_item.placeholder || '选择月'"
           @input="changeHandle(_item, _index)" clearable>
          </el-date-picker>
          <el-time-picker v-if="_item.type === 'time'" :style="{ width: _item.width || '120px' }"
           v-model.trim="formSource.ruleForm[_item.key]" :disabled="_item.disabled" align="right"
           :type="_item.type"
           :size="formOptions.size" :placeholder="_item.placeholder || '选择日期'"
           @input="changeHandle(_item, _index)" clearable>
          </el-time-picker>
        </el-form-item>
      </template>

    </el-form>
  </div>
</template>

<script>
export default {
  name: 'form-content',
  props: {
    // 表单设置
    formOptions: {
      type: Object,
      default: () => ({
        inline: true, // 行内表单模式
        labelPosition: 'right', // 表单域标签的位置，right/left/top
        labelWidth: '150px', // 表单域标签的宽度
        labelSuffix: '', // 表单域标签的后缀
        size: 'small', // 尺寸medium|small|mini
        plain: false // 是否朴素
      })
    },
    // 表单配置
    formSource: {
      type: Object,
      default: () => ({
        // 配置页面控件
        operations: {
          type: Array,
          default: () => [{
            name: '名称',
            key: '查询值绑定字段',
            value: '默认值',
            type: '表单组件类型', // place占位符，其他类型参照element-ui文档
            show: false, // 是否显示
            disabled: false, // 表单组件是否禁用
            placeholder: '表单组件提示语',
            labelWidth: '10px', // 单个lable宽度
            width: '100px', // 表单组件宽度
            formWidth: '110px', // 表单+lable宽度
            length: 15, // 输入框最大输入长度
            numberControlsPosition: 'right', // number控制按钮位置
            numberStep: 1, // number计数器步长
            numberMin: 1, // number计数器允许的最小值
            numberMax: 100, // number计数器允许的最大值
            cascaderOptions: [], // cascader可选项数据源,键名可通过 Props 属性配置
            cascaderProps: {}, // cascader配置选项,具体见https://element.eleme.cn/2.13/#/zh-CN/component/cascader
            cascaderShowAllLevels: false, // cascader输入框中是否显示选中值的完整路径
            cascaderFilterable: false, // cascader是否可搜索
            switchAactiveValue: true, // switch 打开时的值,boolean / string / number
            switchInAactiveValue: false, // switch 关闭时的值,boolean / string / number
            switchValidate: true, // 改变 switch 状态时是否触发表单的校验
            avatarShape: 'circle', // avatar设置头像的形状,circle / square
            avatarFit: 'cover', // 当展示类型为图片的时候，设置图片如何适应容器框,fill / contain / cover / none / scale-down
            avatarSize: 'large', // 设置头像的大小,number / large / medium / small
            tagClosable: false, // tag是否可以删除
            tagType: 'danger', // tag类型，success/info/warning/danger
            multiple: false, // 下拉框是否多选
            collapseTags: false, // 下拉框所选时是否将选中值按文字的形式展示
            filterable: false, // 下拉框是否可搜索
            list: { // 复选框、单选框或者下拉框
              type: Array,
              default: () => [{
                key: 'key',
                value: 'value'
              }]
            }
          }]
        },
        // 表单显示数据
        ruleForm: {
          type: Object,
          default: () => ({})
        },
        // 表单校验规则
        rules: {
          type: Object,
          default: () => ({
            'operations.key': [{ required: true, message: '请输入', trigger: ['blur', 'change'] }]
          })
        }
      })
    }
  },
  data() {
    return {
      // input类型为autocomplete时动态过滤的数组
      restaurants: [],
      formItemIndex: 0,
      formatYear() {
        let dateList = []
        for (let i = 0; i < 7; i++) {
          dateList.push(new Date().getFullYear() + i - 5)
        }
        let select = []
        dateList.forEach(item => {
          let obj = {
            key: item,
            value: item
          }
          select.push(obj)
        })
        return select.reverse()
      },
      formatMonth() {
        return [
          { value: '01', key: '一月' },
          { value: '02', key: '二月' },
          { value: '03', key: '三月' },
          { value: '04', key: '四月' },
          { value: '05', key: '五月' },
          { value: '06', key: '六月' },
          { value: '07', key: '七月' },
          { value: '08', key: '八月' },
          { value: '09', key: '九月' },
          { value: '10', key: '十月' },
          { value: '11', key: '十一月' },
          { value: '12', key: '十二月' }
        ]
      }
    }
  },
  created() {
    this.formSource.operations.forEach(item => {
      if (item.show === undefined) {
        item.show = true
      }
    })
  },
  beforeUpdate() {},
  computed: {
    defaultAvatar: {
      get () { return this.$store.getters.defaultAvatar }
    }
  },
  methods: {
    init() {
      this.update()
      this.$refs.ruleForm.resetFields()
      this.clearValidate()
    },
    update() {
      this.$forceUpdate()
    },
    clearValidate() {
      this.$refs.ruleForm.clearValidate()
    },
    // autocomplete动态设定数组
    setAutocompleteArr(_item, index) {
      this.restaurants = _item.list
      this.formItemIndex = index
    },
    // autocomplete当选择是下拉中的数据时,可触发的事件
    autoSelectHandle(_item) {
      // 解决从下面选中触发必填验证
      this.$refs.ruleForm.clearValidate(this.formSource.operations[this.formItemIndex].key)
      this.$emit('autoSelectHandle', { 'backData': _item })
    },
    // autocomplete输入时的过滤方法
    querySearch(queryString, cb) {
      let restaurants = this.restaurants
      let results = queryString ? restaurants.filter(this.createFilter(queryString)) : restaurants
      // 调用 callback 返回建议列表的数据
      cb(results)
    },
    // autocomplete自定义过滤
    createFilter(queryString) {
      return (restaurant) => {
        return (restaurant.value.toLowerCase().indexOf(queryString.toLowerCase()) === 0)
      }
    },
    // 表单组件值发生变化
    changeHandle(_item, _index, _value) {
      if (_item.type.indexOf('range') !== -1) {
        let newKey = _item.key.charAt(0).toUpperCase() + _item.key.slice(1)
        let values = this.formSource.ruleForm[_item.key]
        this.$set(this.formSource.ruleForm, 'min' + newKey, values ? values[0] : null)
        this.$set(this.formSource.ruleForm, 'max' + newKey, values ? values[1] : null)
      }
      if (_item.type.indexOf('tag') !== -1) {
        this.formSource.ruleForm[_item.key].splice(this.formSource.ruleForm[_item.key].indexOf(_value), 1)
      }
      this.$emit('changeHandle', { 'backData': _item, _index })
    },
    showHandle(_item, _index, e) {
      if (_item.event === 'focus') {
        e.target.blur()
        // input输入框 获取焦点父组件传递callback时间
        // input 类型是text ,event 是focus才会执行
        this.$emit('callback', { 'backData': _item, _index })
      } else {
        return false
      }
    },
    // 表单组件清除
    clearHandle(_item, _index) {
      if (_item.event !== 'focus') {
        for (let field in _item) {
          if (this.formSource.ruleForm[_item[field]] !== undefined) {
            this.formSource.ruleForm[_item[field]] = ''
          }
        }
        this.$emit('clearHandle', { 'backData': _item, _index })
      }
      this.update()
    },
    submitForm() {
      // 表单验证事件 父组件调用
      let result = false
      this.$refs.ruleForm.validate(valid => {
        result = valid
      })
      return result
    }
  }
}
</script>

<style lang="scss" scoped>
.form-content {
  i.el-input__icon.el-icon-edit {
    color: rgba(255, 163, 82, 1);
    cursor: pointer;
    font-size: 16px;
  }

  i.el-input__icon {
    height: auto
  }

  .el-tag.el-tag--danger {
    margin-right: 8px;
  }

  &__operation {
    &-item {
      &-span {
        display: inline-block;
      }
    }
  }
}
</style>
